/*
 * indexed_log.cpp
 *
 *  Created on: 17-May-2011
 *      Author: tan-ce
 */


#include <time.h>
#include <sstream>
#include "indexed_log.h"
#include <iostream>

using namespace std;

IndexedLog::IndexedLog(const char *name) {
	string idx_file((string(name) + ".log.index"));
	idx = fopen(idx_file.c_str(), "a+");
	log = fopen((string(name) + ".log").c_str(), "a+");

	if (log == NULL || idx == NULL) throw IndexedLogError("Could not open log file");
	/* if (idx == NULL) {
		// Rebuild the index file
		idx = fopen(idx_file.c_str(), "w");

		FILE *t = fopen("test.log", "w");

		// An unfortunate loss
		index_entry buf;
		time(&buf.timestamp);

		long prev_off = 0;
		long cur_off = 0;
		fseek(log, 0, SEEK_SET);

		fprintf(t, "Here we go\n");

		do {
			char c;
			fread(&c, 1, 1, log);
			cur_off++;
			if (c == '\n') {
				buf.len = cur_off - prev_off;
				buf.offset = cur_off;
				prev_off = cur_off + 1;
				append_idx_record(&buf);
				fprintf(t, "%d\n", cur_off);
			}
		} while (!feof(log));

		if (prev_off >= cur_off) {
			buf.len = cur_off - prev_off;
			buf.offset = cur_off;
			prev_off = cur_off + 1;
			append_idx_record(&buf);
		}
	} */
}

void IndexedLog::append_log(string msg) {
	msg += "\n";

	index_entry idx_rec;
	time(&idx_rec.timestamp);

	fseek(log, 0, SEEK_END);
	idx_rec.offset = ftell(log);

	idx_rec.len = msg.length();

	fwrite(msg.c_str(), idx_rec.len, 1, log);
	fwrite(&idx_rec, sizeof(index_entry), 1, idx);
	fflush(log);
	fflush(idx);
}

std::string IndexedLog::retrieve_logs(long record, size_t *linecount) {
	long fpos_first = record * sizeof(index_entry), fpos_last, fend;
	static char err_msg[64];

	fseek(idx, 0, SEEK_END);
	fend = ftell(idx);

	if (fpos_first >= fend || *linecount < 1) {
		*linecount = 0;
		return "";
	}

	size_t &lc = *linecount;

	index_entry *idxs = new index_entry[lc];

    fseek(idx, fpos_first, SEEK_SET);
    lc = fread(idxs, sizeof(index_entry), lc, idx);

    if (lc < 1) {
    	delete [] idxs;
    	return "Error reading from log index file!\n";
    }

    size_t tofetch = idxs[lc - 1].len + (idxs[lc - 1].offset - idxs[0].offset);
    fseek(log, idxs[0].offset, SEEK_SET);

    char *buf;
    try {
    	buf = new char[tofetch];
    } catch (std::bad_alloc &) {
    	delete [] idxs;
    	snprintf(err_msg, 64, "Error allocating memory (%d) to retrieve log.", tofetch);
	return err_msg;
    }

    if (fread(buf, tofetch, 1, log) != 1) {
    	delete [] buf;
    	delete [] idxs;
    	return "Error reading from log file!\n";
    }

    stringstream out;
    struct tm *tminfo;
    char time_buf[20];
    unsigned int charoffset = 0;

    for (int i = 0; i < lc; i++) {
    	buf[charoffset + idxs[i].len - 1] = 0;

        tminfo = localtime(&(idxs[i].timestamp));
        strftime(time_buf, 19, "%e %b %H:%M ", tminfo);
    	out << time_buf << &buf[charoffset] << "\n";

    	charoffset += idxs[i].len;
    }

    delete [] buf;
    delete [] idxs;

    return out.str();

	/*fseek(idx, fpos_first, SEEK_SET);
	fread(&first, sizeof(index_entry), 1, idx);

	if (*linecount > 1) {
		index_entry last;

		fpos_last = (record + *linecount - 1) * sizeof(index_entry);
		if (fpos_last >= fend) {
			fpos_last = fend - sizeof(index_entry);
			*linecount = (fpos_last - fpos_first) / sizeof(index_entry) + 1;
		}

		fseek(idx, fpos_last, SEEK_SET);
		fread(&last, sizeof(index_entry), 1, idx);

		tofetch = last.offset - first.offset + last.len;
	} else tofetch = first.len;

	fseek(log, first.offset, SEEK_SET);
	char *buf = new char[tofetch + 1];
	fread(buf, tofetch, 1, log);
	buf[tofetch] = 0;

	string ret(buf);
	delete buf;

	return ret; */
}
